/*-----------------------------------------------------------------------------------*/
/* Nuvoton Corporation confidential                                                  */
/*                                                                                   */
/* Copyright (c) 2009 by Nuvoton Corporation                                         */
/* All rights reserved                                                               */
/*                                                                                   */
/*-----------------------------------------------------------------------------------*/
/* File Contents:                                                                    */
/*   ps2_diag.c                                                                      */
/*                                                                                   */
/* This file contains:                                                               */
/*                                                                                   */
/* Project:                                                                          */
/*                                                                                   */
/* Remark:                                                                           */
/*                                                                                   */
/*-----------------------------------------------------------------------------------*/

#include <stdlib.h>
#include <stdio.h>
#include <string.h>

#include "wblib.h"
#include "NUC900_ps2.h"


/* Keyboard commands */
UINT8 ps2Onledcom[3][2] = {{0xed,0x01},{0xed,0x02},{0xed,0x04}};  // turn on ps2 keyboard led command
UINT8 ps2Offledcom[2] = {0xed,0x00};							  // turn off ps2 keyborad led command
UINT8 ps2KBReset[1] = {0xFF};									  // keyboard reset command

/* Mouse definitions */
UINT8 ps2SetScale = 0xE6;
UINT8 ps2SetSampleRate = 0xF3;
UINT8 ps2EnableDataReport = 0xF4;
UINT8 ps2MouseReset = 0xFF;

volatile int packetcnt = 0;
volatile int gfLeftButton = 0;
volatile int gfRightButton = 0;
volatile int gfMidButton = 0;
volatile int gXmov_flag, gYmov_flag, gXmov_data, gYmov_data; 

unsigned char pktdata[3];

/*  */
int port;
PS2_DATA_T rxb[20];

void PS2MouseCallBackDemo (void);
int MouseStatusDetection (void);


//------------------------- Program -------------------------//
void MouseTestItem (void)
{
	sysprintf("\n");
	sysprintf("+-------------------------------------+\n");
	sysprintf("|   PS2 Mouse Test Items              |\n");
	sysprintf("+-------------------------------------+\n");
	sysprintf("| Get data from mouse             -[0]|\n");
	sysprintf("+-------------------------------------+\n");
	sysprintf("| Exit demo program               -[q]|\n");
	sysprintf("+-------------------------------------+\n");	
}

void KeyboardTestItem (void)
{
	sysprintf("\n");
	sysprintf("+-------------------------------------+\n");
	sysprintf("|   PS2 Keyboard Test Items           |\n");
	sysprintf("+-------------------------------------+\n");
	sysprintf("| Scroll Lock LED on              -[0]|\n");
	sysprintf("| Num Lock LED on                 -[1]|\n");
	sysprintf("| Caps Lock LED on                -[2]|\n");
	sysprintf("| Keyboard reset                  -[3]|\n");
	sysprintf("| Get data from keyboard          -[4]|\n");
	sysprintf("+-------------------------------------+\n");
	sysprintf("| Exit demo program               -[q]|\n");
	sysprintf("+-------------------------------------+\n");	
}

int MouseTest (void)
{
	int volatile retval, stime;
	UINT8 rate = 0x28;
	
	/* reset mouse */
	retval = ps2Write(port, &ps2MouseReset, 1);
	if (retval < 0)
	{
		sysprintf("\n Reset mouse fail!\n");
		return -1;
	}
	else
		sysprintf("\n Reset mouse success\n");	
		
	/* configure mouse settings */
	retval = ps2Write(port, &ps2SetScale, 1);
	if (retval < 0)
		return -1;
	
	retval = ps2Write(port, &ps2SetSampleRate, 1);
	if (retval < 0)
		return -1;
	
	retval = ps2Write(port, &rate, 1);  /* 40 samples/sec */
	if (retval < 0)
		return -1;
	
	retval = ps2Write(port, &ps2EnableDataReport, 1);
	if (retval < 0)
		return -1;
	
	/* flush PS2 Rx buffer for the following test */
	retval = ps2Ioctl(port, PS2_IOC_FLUSH_RX_BUFFER, 0, 0);
	if (retval != 0)
	{
		sysprintf("\n Flush Rx buffer fail!\n");	
		return -1;
	}	
	
	retval = ps2Ioctl(port, PS2_IOC_SET_RX_MODE, PS2_NON_BLOCK, 0);
	if (retval != 0)
		return -1;
		
	retval = ps2Ioctl(port, PS2_IOC_SET_CALLBACK_FUN, (UINT32)PS2MouseCallBackDemo, 0);
	if (retval != 0)
		return -1;
	
	sysprintf("\n Start to test\n");
	
	#if 0
	while(1);  /* wait for mouse packet */	
	#else
	stime = sysGetTicks(TIMER0);
	while(1)
	{
		if ( (sysGetTicks(TIMER0) - stime) > 500 )  /* test 5 sec */
		{
			//sysprintf("exit ...\n");
			break;
		}
	}
	return 0;
	#endif
}

void PS2MouseCallBackDemo (void)
{
	int retval;
	int old_lbutton, old_rbutton, old_mbutton;
	
	packetcnt++;
	
	/* a entire mouse data includes 3 packets */	
	if (packetcnt >= 3)  
	{
		packetcnt -= 3;	
		
		retval = ps2Read(port, (PUINT8)&rxb, 3);
		if (retval == 3)
		{
			pktdata[0] = rxb[0].ucScanCode;
			pktdata[1] = rxb[1].ucScanCode;
			pktdata[2] = rxb[2].ucScanCode;
			
			/* keep old button status */
			old_lbutton = gfLeftButton;
			old_rbutton = gfRightButton;
			old_mbutton = gfMidButton;
			
			/* check button status and movement */
			MouseStatusDetection();
			
			sysprintf("\nMove Packet : \n");	
			
			/* print left button message */
			if (old_lbutton != gfLeftButton)
			{
				sysprintf("     Left button->");
			
				if (gfLeftButton)
					sysprintf("press\n");
				else
					sysprintf("release\n");
			}
		
			/* print right button message */
			if (old_rbutton != gfRightButton)
			{
				sysprintf("     Right button->");
			
				if (gfRightButton)
					sysprintf("press\n");
				else
					sysprintf("release\n");
			}
		
			/* print middle button message */
			if (old_mbutton != gfMidButton)
			{
				sysprintf("     Middle button->");
			
				if (gfMidButton)
					sysprintf("press\n");
				else
					sysprintf("release\n");
			}
		
			/* print X & Y movement message */			
			sysprintf("     X Movement : %c%d\n", (gXmov_flag < 0) ? '-':'+', gXmov_data);							
			sysprintf("     Y Movement : %c%d\n", (gYmov_flag < 0) ? '-':'+', gYmov_data);
			sysprintf("--------------------------------\n");
		}
		else
			sysprintf("Get mouse packet fail!\n");
	}
}

int MouseStatusDetection (void)
{
	/* button status */
	if (pktdata[0] & 0x01)
		gfLeftButton = TRUE;
	else
		gfLeftButton = FALSE;
	
	if (pktdata[0] & 0x02)
		gfRightButton = TRUE;
	else
		gfRightButton = FALSE;
	
	if (pktdata[0] & 0x04)
		gfMidButton = TRUE;
	else
		gfMidButton = FALSE;

	/* X movement */
	if (pktdata[0] & 0x10)
	{
		gXmov_flag = -1;
		gXmov_data = (int) (((~pktdata[1]) + 1) & 0xFF);
	}
	else
	{
		gXmov_flag = 1;											
		gXmov_data = (int) pktdata[1];
	}
	
	/* Y movement */	
	if (pktdata[0] & 0x20)
	{
		gYmov_flag = -1;
		gYmov_data = (int) (((~pktdata[2]) + 1) & 0xFF);
	}
	else
	{
		gYmov_flag = 1;
		gYmov_data = (int) pktdata[2]; 	
	}
		
	return 0;
} 

void ps2testmsg_kb(void)
{
	int ch;
	
	sysprintf("Description: Send commands to PS/2 keyboard and get data from PS/2 keyboard.\n");
	sysprintf("             Plug in keyboard first.\n");
	sysprintf("Test   Tool: PS/2 Keyboard.\n");
#if defined(NUC951)
	sysprintf("H/W Setting: Switch9 ON.\n");
#else	
	sysprintf("H/W Setting: Switch5,1-8 ON. Switch6,1-8 OFF. Switch7,1-8 OFF.\n");
#endif	
	sysprintf("Test Result: Program should print test message.\n");
	
	sysprintf("\nAny key start test ...\n");
	ch = sysGetChar();
}

void ps2testmsg_mouse(void)
{
	int ch;
	
	sysprintf("Description: Get data packet from PS/2 mouse. Plug in mouse first.\n");
	sysprintf("             Test 5 second then exit test.\n");
	sysprintf("Test   Tool: PS/2 Mouse.\n");
#if defined(NUC951)
	sysprintf("H/W Setting: Switch9 ON.\n");
#else	
	sysprintf("H/W Setting: Switch5,1-8 ON. Switch6,1-8 OFF. Switch7,1-8 OFF.\n");
#endif	
	sysprintf("Test Result: Program should print test message.\n");
	
	sysprintf("\nAny key start test ...\n");
	ch = sysGetChar();
}


INT diag_ps2(VOID)
{
	int ch, retval, cnt;
	int volatile stime;
	
	sysprintf("\n\n PS2 diagnostic test\n\n");
	
	//sysSetTimerReferenceClock(TIMER0, 15000000);
	//sysStartTimer(TIMER0, 100, PERIODIC_MODE);
	
	/* select PS2 device */
	while (1)
	{
		sysprintf("\n Select PS2 device, keyboard/mouse [0/1]\n");
		ch = sysGetChar();
		if ( (ch == '0') || (ch == '1') )
			break;
	}
	sysprintf(" [%s] selected\n\n", (ch == '0') ? "Keyboard" : "Mouse");
	
	if (ch == '0')  
	{
		/* Keyboard test */
		ps2testmsg_kb();
		
		/* select PS2 port */
		while (1)
		{
			sysprintf("\n Select PS2 channel [0/1]\n");
			ch = sysGetChar();
			if ( (ch == '0') || (ch == '1') )
				break;
		}
				
		if (ch == '0')
			port = PS2_PORT0;
		else
			port = PS2_PORT1;
				
		sysprintf(" Channel[%d] selected\n", port);	
		
		/* initialize PS2 */
		ps2Init();
		retval = ps2Open(port, PS2_KEYBOARD);
		if (retval != 0)
		{
			sysprintf("\n Open PS2 device fail!\n");	
			return 0;
		}
		else
			sysprintf("Open PS2[%d] success\n", port);
				
		do
		{
			KeyboardTestItem();
			ch = sysGetChar();			
			switch(ch)
			{
				/* Scroll Lock LED on */
				case '0':
					retval = ps2Write(port, &ps2Onledcom[0][0], 2);
					if(retval > 0)
						sysprintf("\n Send scroll lock command success\n");
					else
						sysprintf("\n Send scroll lock command fail[%x]\n", retval);	
				
					break;
			
				/* Num Lock LED on */
				case '1':
					retval = ps2Write(port, &ps2Onledcom[1][0], 2);
					if(retval > 0)
						sysprintf("\n Send Num lock command success\n");
					else
						sysprintf("\n Send Num lock command fail[%x]\n", retval);	
					
					break;
				
				/* Caps Lock LED on */
				case '2':
					retval = ps2Write(port, &ps2Onledcom[2][0], 2);
					if(retval > 0)
						sysprintf("\n Send Caps lock command success\n");
					else
						sysprintf("\n Send Caps lock command fail[%x]\n", retval);	
					
					break;
					
				/* Keyboard reset */	
				case '3':
					retval = ps2Write(port, ps2KBReset, 1);
					if(retval > 0)
						sysprintf("\n Keyboard reset success\n");
					else
						sysprintf("\n Keyboard reset fail[%x]\n", retval);	
									
					break;	
				
				/* Get data from device */
				case '4':
					retval = ps2Ioctl(port, PS2_IOC_FLUSH_RX_BUFFER, 0, 0);
					if (retval != 0)
					{
						sysprintf(" Flush RX buffer fail!\n");
						break;	
					}
					
					sysprintf("\n Set trap shift mode, enable/disable [0/1]\n");
					ch = sysGetChar();
					if ( (ch != '0') && (ch != '1') )
						ch = '0';
						
					if (ch == '0')
					{
						sysprintf(" Enable trap shift\n\n");
						retval = ps2Ioctl(port, PS2_IOC_SET_TRAP_SHIFT, PS2_ENABLE_TRAP_SHIFT, 0);
						if (retval != 0)
						{
							sysprintf(" Enable trap shift fail!\n");
							break;	
						}
					}	
					else
					{
						sysprintf(" Disable trap shift\n\n");
						retval = ps2Ioctl(port, PS2_IOC_SET_TRAP_SHIFT, PS2_DISABLE_TRAP_SHIFT, 0);
						if (retval != 0)
						{
							sysprintf(" Disable trap shift fail!\n");
							break;	
						}
					}		
					
					sysprintf(" Set released key mode, enable/disable [0/1]\n");
					ch = sysGetChar();
					if ( (ch != '0') && (ch != '1') )
						ch = '0';
						
					if (ch == '0')
					{
						sysprintf(" Enable released key\n\n");
						retval = ps2Ioctl(port, PS2_IOC_SET_RX_RELEASE, PS2_ENABLE_RX_RELEASE, 0);
						if (retval != 0)
						{
							sysprintf(" Enable released key fail!\n");
							break;	
						}
					}	
					else
					{
						sysprintf(" Disable released key\n\n");
						retval = ps2Ioctl(port, PS2_IOC_SET_RX_RELEASE, PS2_DISABLE_RX_RELEASE, 0);
						if (retval != 0)
						{
							sysprintf(" Disable released key fail!\n");
							break;	
						}
					}
					
					#if 0
					sysprintf(" Set RX operation mode, block/non-block [0/1]\n");
					ch = sysGetChar();
					if ( (ch != '0') && (ch != '1') )
						ch = '0';
						
					if (ch == '0')
					{
						sysprintf(" Block mode\n\n");
						retval = ps2Ioctl(port, PS2_IOC_SET_RX_MODE, PS2_BLOCK, 0);
						if (retval != 0)
						{
							sysprintf(" Set block mode fail!\n");
							break;	
						}
					}	
					else
					{
						sysprintf(" Non-block mode\n\n");
						retval = ps2Ioctl(port, PS2_IOC_SET_RX_MODE, PS2_NON_BLOCK, 0);
						if (retval != 0)
						{
							sysprintf(" Set non-block fail!\n");
							break;	
						}
					}	
					#else
					sysprintf(" Non-block mode\n\n");
					retval = ps2Ioctl(port, PS2_IOC_SET_RX_MODE, PS2_NON_BLOCK, 0);
					if (retval != 0)
					{
						sysprintf(" Set non-block fail!\n");
						break;	
					}
					#endif
					
					sysprintf("Start to test. Press ESC to stop test.\n");
					cnt = 0;
					
					stime = sysGetTicks(TIMER0);	
					rxb[0].ucAsciiCode = 0;
					while(1)
					{
						retval = ps2Read(port, (PUINT8)&rxb, 1);	
						if (retval > 0)
						{
							sysprintf("%d scan[0x%02x] ascii[0x%02x] %c\n", cnt + 1, rxb[0].ucScanCode, 
								rxb[0].ucAsciiCode, rxb[0].ucAsciiCode);
								
							cnt += retval;
						}	
						
						if (rxb[0].ucAsciiCode == 0x1B)
							break;
						
						if (inpw(0xB8000014) & 0x01)
						{
							if (sysGetChar() == 0x1B)
								break;
						}
					}
					break;
				
				default:
					break;
			}			
		}while(ch != 'q');

		sysprintf("\n Exit keyboard test program ...\n");		
		ps2Release(port);
	}
	else           
	{
		 /* Mouse test */
		ps2testmsg_mouse();
		
		/* select PS2 port */
		while (1)
		{
			sysprintf("\n Select PS2 channel [0/1]\n");
			ch = sysGetChar();
			if ( (ch == '0') || (ch == '1') )
				break;
		}
				
		if (ch == '0')
			port = PS2_PORT0;
		else
			port = PS2_PORT1;
				
		sysprintf(" Channel[%d] selected\n", port);	
		
		/* initialize PS2 */
		ps2Init();
		retval = ps2Open(port, PS2_MOUSE);
		if (retval != 0)
		{
			sysprintf("\n Open PS2 device fail!\n");	
			return 0;
		}
		else
			sysprintf(" Open PS2[%d] success\n", port);
				
		MouseTestItem();
		do
		{
			ch = sysGetChar();			
			switch(ch)
			{
				/* Get data from mouse */
				case '0':
					retval = MouseTest();
					if (retval < 0)
					{
						ps2Ioctl(port, PS2_IOC_GET_ERR_STATUS, (UINT32) &retval, 0);
						sysprintf(" Mouse test failed [0x%08x].\n", retval);
					}
					break;
					
				default:
					break;	
			}		
		}	while ((ch != 'q') && (ch != 0x1B));
		
		sysprintf("\n Exit mouse test program ...\n");		
		ps2Release(port);
	}		
	
	return 0;
}
